﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using XDL.Framework.Weapons;
using XDL.Framework;
using XDL.Framework.Collections;
using JumpNFight.Simulation;
using XDL.Framework.Particles;

namespace JumpNFight.Weapons
{
    class FlameThrowerWeaponSystem : 
        IWeapon,
        IWeaponSystem,
        UpdatableArray<FlameParticle>.Client
    {
        public const int FryEvent = 10001;

        Timer m_smokeTimer = new Timer(TimeSpan.FromSeconds(0.25),true);
        ParticleSystem m_smokePS;
        World m_world;
        AudioManager m_audio;
        UpdatableArray<FlameParticle> m_flames;
        FlameEmitter[] m_flameEmitters = new FlameEmitter[World.MaxPlayers];
        
        readonly static Random Rnd = new Random();

        WeaponSettings m_settings;
        public WeaponSettings Settings
        {
            get 
            {
                return m_settings;
            }
        }

        public FlameThrowerWeaponSystem(Game game)
        {
            m_flames = new UpdatableArray<FlameParticle>(512, this);
        }

        public void Initialize()
        {
            m_settings = GameServices.LoadContent<WeaponSettings>("Weapons/FlameThrower");
            m_audio = GameServices.GetService<AudioManager>();
            m_world = GameServices.GetService<World>();
            m_smokePS = GameServices.GetService<ParticleSystem>("Particles/FlameSmoke");            
            ParticleSystem flamePS = GameServices.GetService<ParticleSystem>("Particles/Flame");
            for (int i = 0; i < World.MaxPlayers; i++)
                m_flameEmitters[i] = new FlameEmitter(flamePS, 60);
        }

        bool m_spawnSmoke = false;
        public void Update(GameTime gameTime)
        {
            m_smokeTimer.Update(gameTime);
            if (m_smokeTimer.IsSignaled)
            {
                m_spawnSmoke = true;
                m_smokeTimer.Reset(TimeSpan.FromSeconds(0.25 * Rnd.NextDouble()));
            }

            m_flames.Update(gameTime);    

            m_spawnSmoke = false;
        }

        public void Fire(int ownerID, Vector3 position, Vector3 direction)
        {            
            // Fill in the particle vertex structure.
            FlameParticle newParticle = new FlameParticle();
            newParticle.OwnerID = ownerID;
            newParticle.Position = new Vector2(position.X, position.Y);

            // Adjust the input velocity based on how much
            // this particle system wants to be affected by it.
            direction *= 200;
            // Add in some random amount of vertical velocity.
            direction.Y += MathHelper.Lerp(-20,5,(float)Rnd.NextDouble());
            newParticle.Velocity = new Vector2(direction.X, direction.Y);
            // set the age
            newParticle.Lifetime = 0.8f + (float)(0.3 * Rnd.NextDouble());
            // add the 4 corners
            m_flames.Add(newParticle);

            // per-weapon sound
            m_audio.PlayCue(Settings.Name + "/Fire");
        }

        public bool Update(GameTime gameTime, ref FlameParticle item)
        {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            item.Lifetime -= dt;
            if (item.Lifetime > 0)
            {
                FlameParticle oldParticle = item;
                m_world.AdjustPoint(ref item.Position, ref item.Velocity, ref item.IsTouchingGround, 20, 1.9f, gameTime);
                
                // 
                Intersect(ref item);
                if (item.IsTouchingGround && m_spawnSmoke)
                    m_smokePS.AddParticle(new Vector3(item.Position.X, item.Position.Y, 0), Vector3.Zero);

                m_flameEmitters[item.OwnerID].Update(gameTime, oldParticle, ref item);
              
                return true;
            }

            return false;
        }

        protected void Intersect(ref FlameParticle item)
        {
            BoundingSphere bs = new BoundingSphere(new Vector3(item.Position.X, item.Position.Y, 0), 8);
            foreach (BadGuy it in m_world.NPCs)
            {
                if (it.IsAlive && it.Moveable.Intersects(bs))
                {
                    GameServices.EventDispatcher.PostEvent(it.ID, NPCBase.HitEvent, new WeaponHitEventArgs(item.OwnerID, this.Settings));
                    GameServices.EventDispatcher.PostEvent(item.OwnerID, Player.RegisterHitEvent, null);
                }
            }

            if (item.IsTouchingGround)
            {
                foreach (Player it in m_world.Players)
                {
                    if (it.IsAlive && it.Moveable.Intersects(bs))
                    {
                        GameServices.EventDispatcher.PostEvent(it.ID, FlameThrowerWeaponSystem.FryEvent, new FlameWeaponHitEventArgs(item.OwnerID, this.Settings, item.Position));
                    }
                }
            }
        }

        public void Copy(ref FlameParticle item, ref FlameParticle targetItem)
        {            
            targetItem.IsTouchingGround = item.IsTouchingGround;
            targetItem.OwnerID = item.OwnerID;
            targetItem.Dt = item.Dt;
            targetItem.Lifetime = item.Lifetime;
            targetItem.Position = item.Position;
            targetItem.Velocity = item.Velocity;
        }

        public void Clear()
        {
            m_flames.Clear();
        }
    }
}
